#include <gtest/gtest.h>

#include <memory>

class IChannel {
public:
    virtual ~IChannel(){}

    virtual bool open() = 0; 
    virtual bool close() = 0;

    int write(const char *str){
        return write(str, strlen(str));
    }
    int write(const std::string & str) {
        return write(str.c_str(), str.size());
    }
    virtual void write(const char * buf, int size) = 0; 
    virtual void disconnect() = 0;
};

class IChannelHandler {
public:
    virtual ~IChannelHandler() {
    }
    virtual void connected(IChannel* channel) = 0;
    virtual void disconnected(IChannel* channel, int error) = 0;

    virtual void read(IChannel * channel, const char * buf,  std::size_t size) = 0;
    virtual void readException(IChannel * channel, int error) = 0 ;

    virtual void writed(IChannel * channel, std::size_t size) = 0 ;
    virtual void writeException(IChannel * channel, int error) = 0;
};



/*
 *   MyDesign 
IChannelHandler --> ChannelHandler

IChannel --> Channel


IService --> IClient, IServer,


IChannel --> HeartBeatChannel :: checkRecvTimespan, checkSendTimespan
IClient --> HeartBeatClient ::  checkRecvTimespan, checkSendTimespan
IServer --> HeartBeatServer ::  checkRecvTimespan, checkSendTimespan

IBuffer --> WriteBuffer, ReadBuffer, GatherBuffer, Sca

ITimerTask 
IService --> ITimer

IProtocol

ISyncChannel
ISyncChannelHandler
ISyncService --> ISyncClient, ISyncServer //Special Case


-----  Implementation -->
Channel --<> ChannelImp --> AsioChannelImp;  socket,
??? ClientChannelImp --> AsioClientChannelImp ;    socket, impFactory->createClientChannel();
??? ServerChannelImp --> AsioServerChannelImp; socket; impFactory->createServerChannel();

ClientImp --> AsioClientImp;
ServerImp --> AsioServerImp;
Timer  --> AsioTimerImp 


AsioImpFactory ::
    createClientImp, createClientChannelImp, createTimerImp
    createServerImp, createServerChannelImp, createTimerImp
    createBuffer 

*/





class Client {
    IChannel * connect(){
        ChannelImp * channelImp = clientImp->connect();
    };
}








class Client {
public:
    virtual ~Client(){}
    ClientChannel connect();
}

class ClientChannel : public IChannel {
public:
    ClientChannel(Client * client)
    : Client(client)
    {
    }
    ~ClientChannel() override {
    }
    Client * getClient(){
        return client;
    }
    void setClient(Client * client){
        if(this->client != client)
            this->client = client;
    }
private:
    Client * client;
};
class ClientChannelHandler : public IChannelHandler{
public:
};

class Client {
public:
    virtual ~Client(){};
    void setChannelHandler(){
    }
    ClientChannelHandler * getChannelHandler(){
        return nullptr;
    }

    virtual ClientChannel *  connect(const std::string & remoteIp, const int remotePort){
        return new ClientChannel();
    }
    virtual int start(){
        return 0;
    }
    virtual void stop(){
    }
private:
};

TEST(ClientTest, use){
    const char * remoteIp = "127.0.0.1";
    int remotePort = 1234;

    auto client = std::make_shared<Client>();
    client->setHandler(nullptr);

    std::unique_ptr<IClientChannel> cc(client->connect(remoteIp, remotePort));
    cc->setChannelHandler(nullptr);

    ASSERT_TRUE(cc != nullptr);
    ASSERT_EQ(11, cc->write("hello world"));
    ASSERT_EQ(14, cc->write("hello workd2 !"));

    client->start();

    util::waitMs(100);

    client->stop();
}
